﻿using System;
using System.Collections.Generic;
using System.ComponentModel;

namespace Demos.DataStructures
{
    class ObservableMaxHeap: Algoritmia.DataStructures.PriorityQueues.MaxHeap<int>, INotifyPropertyChanged
    {
        protected List<int> heapVisual;
        public event PropertyChangedEventHandler PropertyChanged;
        readonly protected Func<string,int> disparaCambio;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
            disparaCambio(info);
        }

        public ObservableMaxHeap(Func<string,int> disparaCambio)
        {
            this.disparaCambio = disparaCambio;
            heapVisual = new List<int>();
        }

        public override void Add(int elem)
        {
            _count++;
            if (_count == _heap.Length)
            {
                Array.Resize<int>(ref _heap, _heap.Length * 2);
            }
            _heap[_count] = elem;
            NotifyPropertyChanged("Add");
            BubbleUp(_count);
        }

        protected override void Heapify(int index)
        {
            int left, right, best;

            best = index;
            while (true)
            {
                left = 2 * index;
                right = 2 * index + 1;
                if (left <= this._count && _firstHasHigherPriority(_heap[left], _heap[index]))
                {
                    best = left;
                }
                if (right <= this._count && _firstHasHigherPriority(_heap[right], _heap[best]))
                {
                    best = right;
                }
                if (best == index) break;

                Swap(index, best);
                NotifyPropertyChanged("Swap "+(index-1).ToString()+" "+(best-1).ToString());
                index = best;
            }

            NotifyPropertyChanged("Heapify");
        }

        protected override void BubbleUp(int index)
        {
            int parent = index / 2;
            while (index > 1 && _firstHasHigherPriority(_heap[index], _heap[parent]))
            {
                Swap(parent, index);
                NotifyPropertyChanged("Swap " + (parent-1).ToString() + " " + (index-1).ToString());
                index = parent;
                parent = parent / 2;
            }

            NotifyPropertyChanged("BubbleUp");
        }

        public override int ExtractOptimal()
        {
            if (_count == 0)
                throw new InvalidOperationException("This heap is empty.\r\n Add some elements to extract the optimal");
            int value = _heap[1];
            _heap[1] = _heap[_count];
            _count--;
            if (_count > 1) Heapify(1);
            NotifyPropertyChanged("ExtractOptimal");
            return value;
        }

        public void Igualar()
        {
            heapVisual = new List<int>();
            foreach (var item in _heap)
                heapVisual.Add(item);
        }
    }
}
